home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / system-tools-backends-2.0 / scripts / Users / Users.pm < prev   
Encoding:
Perl POD Document  |  2009-04-09  |  20.7 KB  |  811 lines

  1. #-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2. # Users account manager. Designed to be architecture and distribution independent.
  3. #
  4. # Copyright (C) 2000-2001 Ximian, Inc.
  5. #
  6. # Authors: Hans Petter Jansson <hpj@ximian.com>,
  7. #          Arturo Espinosa <arturo@ximian.com>,
  8. #          Tambet Ingo <tambet@ximian.com>.
  9. #          Grzegorz Golawski <grzegol@pld-linux.org> (PLD Support)
  10. #
  11. # This program is free software; you can redistribute it and/or modify
  12. # it under the terms of the GNU Library General Public License as published
  13. # by the Free Software Foundation; either version 2 of the License, or
  14. # (at your option) any later version.
  15. #
  16. # This program is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. # GNU Library General Public License for more details.
  20. #
  21. # You should have received a copy of the GNU Library General Public License
  22. # along with this program; if not, write to the Free Software
  23. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  24.  
  25. # Best viewed with 100 columns of width.
  26.  
  27. # Configuration files affected:
  28. #
  29. # /etc/passwd
  30. # /etc/group
  31. # /etc/shadow
  32. # /etc/login.defs
  33. # /etc/shells
  34. # /etc/skel/
  35.  
  36. # NIS support will come later.
  37.  
  38. # Running programs affected/used:
  39. #
  40. # adduser: creating users.
  41. # usermod: modifying user data.
  42. # passwd: assigning or changing passwords. (Un)locking users.
  43. # chfn: modifying finger information - Name, Office, Office phone, Home phone.
  44. # pw: modifying users/groups and user/group data on FreeBSD.
  45.  
  46. package Users::Users;
  47.  
  48. use Utils::Util;
  49. use Utils::Report;
  50. use Utils::File;
  51. use Utils::Backend;
  52. use Utils::Replace;
  53.  
  54. # --- System config file locations --- #
  55.  
  56. # We list each config file type with as many alternate locations as possible.
  57. # They are tried in array order. First found = used.
  58. @passwd_names =     ( "/etc/passwd" );
  59. @shadow_names =     ( "/etc/shadow", "/etc/master.passwd" );
  60. @login_defs_names = ( "/etc/login.defs", "/etc/adduser.conf" );
  61. @shell_names =      ( "/etc/shells" );
  62. @skel_dir =         ( "/usr/share/skel", "/etc/skel" );
  63.  
  64. # Where are the tools?
  65. $cmd_usermod  = &Utils::File::locate_tool ("usermod");
  66. $cmd_userdel  = &Utils::File::locate_tool ("userdel");
  67. $cmd_useradd  = &Utils::File::locate_tool ("useradd");
  68.  
  69. $cmd_adduser  = &Utils::File::locate_tool ("adduser");
  70. $cmd_deluser  = &Utils::File::locate_tool ("deluser");
  71.  
  72. $cmd_chfn     = &Utils::File::locate_tool ("chfn");
  73. $cmd_pw       = &Utils::File::locate_tool ("pw");
  74.  
  75. # enum like for verbose group array positions
  76. my $i = 0;
  77. my $LOGIN   = $i++;
  78. my $PASSWD  = $i++;
  79. my $UID     = $i++;
  80. my $GID     = $i++;
  81. my $COMMENT = $i++;
  82. my $HOME    = $i++;
  83. my $SHELL   = $i++;
  84.  
  85. %login_defs_prop_map = ();
  86. %profiles_prop_map = ();
  87.  
  88. sub get_login_defs_prop_array
  89. {
  90.   my @prop_array;
  91.   my @login_defs_prop_array_default =
  92.     (
  93.      "QMAIL_DIR",      "qmail_dir",
  94.      "MAIL_DIR",       "mailbox_dir",
  95.      "MAIL_FILE",      "mailbox_file",
  96.      "PASS_MAX_DAYS",  "pwd_maxdays",
  97.      "PASS_MIN_DAYS",  "pwd_mindays",
  98.      "PASS_MIN_LEN",   "pwd_min_length",
  99.      "PASS_WARN_AGE",  "pwd_warndays",
  100.      "UID_MIN",        "umin",
  101.      "UID_MAX",        "umax",
  102.      "GID_MIN",        "gmin",
  103.      "GID_MAX",        "gmax",
  104.      "USERDEL_CMD",    "del_user_additional_command",
  105.      "CREATE_HOME",    "create_home",
  106.      "", "");
  107.  
  108.   my @login_defs_prop_array_suse =
  109.     (
  110.      "QMAIL_DIR",      "qmail_dir",
  111.      "MAIL_DIR",       "mailbox_dir",
  112.      "MAIL_FILE",      "mailbox_file",
  113.      "PASS_MAX_DAYS",  "pwd_maxdays",
  114.      "PASS_MIN_DAYS",  "pwd_mindays",
  115.      "PASS_MIN_LEN",   "pwd_min_length",
  116.      "PASS_WARN_AGE",  "pwd_warndays",
  117.      "UID_MIN",        "umin",
  118.      "UID_MAX",        "umax",
  119.      "SYSTEM_GID_MIN", "gmin",
  120.      "GID_MAX",        "gmax",
  121.      "USERDEL_CMD",    "del_user_additional_command",
  122.      "CREATE_HOME",    "create_home",
  123.      "", "");
  124.  
  125.   if ($Utils::Backend::tool{"platform"} =~ /^suse/)
  126.   {
  127.     @prop_array = @login_defs_prop_array_suse;
  128.   }
  129.   else
  130.   {
  131.     @prop_array = @login_defs_prop_array_default;
  132.   }
  133.  
  134.   for ($i = 0; $prop_array [$i] ne ""; $i += 2)
  135.   {
  136.     $login_defs_prop_map {$prop_array [$i]}     = $prop_array [$i + 1];
  137.     $login_defs_prop_map {$prop_array [$i + 1]} = $prop_array [$i];
  138.   }
  139. }
  140.  
  141. sub get_profiles_prop_array
  142. {
  143.   my @prop_array;
  144.   my @profiles_prop_array_default =
  145.     (
  146.      "NAME" ,          "name",
  147.      "COMMENT",        "comment",
  148.      "LOGINDEFS",      "login_defs",
  149.      "HOME_PREFFIX",   "home_prefix",
  150.      "SHELL",          "shell",
  151.      "GROUP",          "group",
  152.      "SKEL_DIR",       "skel_dir",
  153.      "QMAIL_DIR" ,     "qmail_dir",
  154.      "MAIL_DIR" ,      "mailbox_dir",
  155.      "MAIL_FILE" ,     "mailbox_file",
  156.      "PASS_RANDOM",    "pwd_random",
  157.      "PASS_MAX_DAYS" , "pwd_maxdays",
  158.      "PASS_MIN_DAYS" , "pwd_mindays",
  159.      "PASS_MIN_LEN" ,  "pwd_min_length",
  160.      "PASS_WARN_AGE" , "pwd_warndays",
  161.      "UID_MIN" ,       "umin",
  162.      "UID_MAX" ,       "umax",
  163.      "GID_MIN" ,       "gmin",
  164.      "GID_MAX" ,       "gmax",
  165.      "USERDEL_CMD" ,   "del_user_additional_command",
  166.      "CREATE_HOME" ,   "create_home",
  167.      "", "");
  168.  
  169.   my @profiles_prop_array_suse =
  170.     (
  171.      "NAME" ,          "name",
  172.      "COMMENT",        "comment",
  173.      "LOGINDEFS",      "login_defs",
  174.      "HOME_PREFFIX",   "home_prefix",
  175.      "SHELL",          "shell",
  176.      "GROUP",          "group",
  177.      "SKEL_DIR",       "skel_dir",
  178.      "QMAIL_DIR" ,     "qmail_dir",
  179.      "MAIL_DIR" ,      "mailbox_dir",
  180.      "MAIL_FILE" ,     "mailbox_file",
  181.      "PASS_RANDOM",    "pwd_random",
  182.      "PASS_MAX_DAYS" , "pwd_maxdays",
  183.      "PASS_MIN_DAYS" , "pwd_mindays",
  184.      "PASS_MIN_LEN" ,  "pwd_min_length",
  185.      "PASS_WARN_AGE" , "pwd_warndays",
  186.      "UID_MIN" ,       "umin",
  187.      "UID_MAX" ,       "umax",
  188.      "GID_MIN" ,       "gmin",
  189.      "GID_MAX" ,       "gmax",
  190.      "USERDEL_CMD" ,   "del_user_additional_command",
  191.      "CREATE_HOME" ,   "create_home",
  192.      "", "");
  193.  
  194.   if ($Utils::Backend::tool{"platform"} =~ /suse/)
  195.   {
  196.     @prop_array = @profiles_prop_array_suse;
  197.   }
  198.   else
  199.   {
  200.     @prop_array = @profiles_prop_array_default;
  201.   }
  202.  
  203.   for ($i = 0; $prop_array[$i] ne ""; $i += 2)
  204.   {
  205.     $profiles_prop_map {$prop_array [$i]}     = $prop_array [$i + 1];
  206.     $profiles_prop_map {$prop_array [$i + 1]} = $prop_array [$i];
  207.   }
  208. }
  209.  
  210. #FIXME: do not hardcode GIDs like that
  211. my $rh_logindefs_defaults = {
  212.   'shell'    => '/bin/bash',
  213.   'group'    => -1,
  214.   'skel_dir' => '/etc/skel/',
  215. };
  216.  
  217. my $gentoo_logindefs_defaults = {
  218.   'shell'    => '/bin/bash',
  219.   'group'    => 100,
  220.   'skel_dir' => '/etc/skel/',
  221. };
  222.  
  223. my $freebsd_logindefs_defaults = {
  224.   'shell'    => '/bin/sh',
  225.   'group'    => -1,
  226.   'skel_dir' => '/etc/skel/',
  227. };
  228.  
  229. my $logindefs_dist_map = {
  230.   'redhat-6.2'      => $rh_logindefs_defaults,
  231.   'redhat-7.0'      => $rh_logindefs_defaults,
  232.   'redhat-7.1'      => $rh_logindefs_defaults,
  233.   'redhat-7.2'      => $rh_logindefs_defaults,
  234.   'redhat-7.3'      => $rh_logindefs_defaults,
  235.   'redhat-8.0'      => $rh_logindefs_defaults,
  236.   'mandrake-9.0'    => $rh_logindefs_defaults,
  237.   'pld-1.0'         => $rh_logindefs_defaults,
  238.   'fedora-1'        => $rh_logindefs_defaults,
  239.   'debian-3.0'      => $rh_logindefs_defaults,
  240.   'debian-3.1'      => $rh_logindefs_defaults,
  241.   'debian-4.0'      => $rh_logindefs_defaults,
  242.   'debian-5.0'      => $rh_logindefs_defaults,
  243.   'debian-testing'  => $rh_logindefs_defaults,
  244.   'vine-3.0'        => $rh_logindefs_defaults,
  245.   'gentoo'            => $gentoo_logindefs_defaults,
  246.   'archlinux'       => $gentoo_logindefs_defaults,
  247.   'slackware-9.1.0' => $gentoo_logindefs_defaults,
  248.   'freebsd-5'       => $freebsd_logindefs_defaults,
  249.   'suse-9.0'        => $gentoo_logindefs_defaults,
  250.   'solaris-2.11'    => $gentoo_logindefs_defaults,
  251. };
  252.  
  253.  
  254. # Add reporting table.
  255.  
  256. &Utils::Report::add ({
  257.   'users_read_profiledb_success' => ['info', 'Profiles read successfully.'],
  258.   'users_read_profiledb_fail'    => ['warn', 'Profiles read failed.'],
  259.   'users_read_users_success'     => ['info', 'Users read successfully.'],
  260.   'users_read_users_fail'        => ['warn', 'Users read failed.'],
  261.   'users_read_groups_success'    => ['info', 'Groups read successfully.'],
  262.   'users_read_groups_fail'       => ['warn', 'Groups read failed.'],
  263.   'users_read_shells_success'    => ['info', 'Shells read successfully.'],
  264.   'users_read_shells_fail'       => ['warn', 'Reading shells failed.'],
  265.  
  266.   'users_write_profiledb_success' => ['info', 'Profiles written successfully.'],
  267.   'users_write_profiledb_fail'    => ['warn', 'Writing profiles failed.'],
  268.   'users_write_users_success'     => ['info', 'Users written successfully.'],
  269.   'users_write_users_fail'        => ['warn', 'Writing users failed.'],
  270.   'users_write_groups_success'    => ['info', 'Groups written successfully.'],
  271.   'users_write_groups_fail'       => ['warn', 'Writing groups failed.'],
  272. });
  273.  
  274.  
  275. sub do_get_use_md5
  276. {
  277.   my ($file) = @_;
  278.   my ($fh, @line, $i, $use_md5);
  279.  
  280.   my $fh = &Utils::File::open_read_from_names ("/etc/pam.d/$file");
  281.   return 0 if (!$fh);
  282.  
  283.   $use_md5 = 0;
  284.  
  285.   while (<$fh>)
  286.   {
  287.     next if &Utils::Util::ignore_line ($_);
  288.     chomp;
  289.     @line = split /[ \t]+/;
  290.  
  291.     if ($line[0] eq "\@include")
  292.     {
  293.       $use_md5 = &do_get_use_md5 ($line[1]);
  294.     }
  295.     elsif ($line[0] eq "password")
  296.     {
  297.       foreach $i (@line)
  298.       {
  299.         $use_md5 = 1 if ($i eq "md5");
  300.       }
  301.     }
  302.   }
  303.  
  304.   close $fh;
  305.   return $use_md5;
  306. }
  307.  
  308. sub get_use_md5
  309. {
  310.   return &do_get_use_md5 ("passwd");
  311. }
  312.  
  313. sub logindefs_add_defaults
  314. {
  315.   # Common for all distros
  316.   my $logindefs = {
  317.     'home_prefix' => '/home/',
  318.   };
  319.  
  320.   &get_profiles_prop_array ();
  321.  
  322.   # Distro specific
  323.   my $dist_specific = $logindefs_dist_map->{$Utils::Backend::tool{"platform"}};
  324.  
  325.   # Just to be 100% sure SOMETHING gets filled:
  326.   unless ($dist_specific)
  327.   {
  328.     $dist_specific = $rh_logindefs_defaults;
  329.   }
  330.  
  331.   foreach my $key (keys %$dist_specific)
  332.   {
  333.     # Make sure there's no crappy entries
  334.     if (exists ($profiles_prop_map{$key}) || $key eq "groups")
  335.     {
  336.       $logindefs->{$key} = $dist_specific->{$key};
  337.     }
  338.   }
  339.   return $logindefs;
  340. }
  341.  
  342. sub get_logindefs
  343. {
  344.   my $logindefs;
  345.  
  346.   &get_login_defs_prop_array ();
  347.   $logindefs = &logindefs_add_defaults ();
  348.  
  349.   # Get new data in case someone has changed login_defs manually.
  350.   my $fh = &Utils::File::open_read_from_names (@login_defs_names);
  351.  
  352.   if ($fh)
  353.   {
  354.     while (<$fh>)
  355.     {
  356.       next if &Utils::Util::ignore_line ($_);
  357.       chomp;
  358.       my @line = split /[ \t]+/;
  359.  
  360.       if (exists $login_defs_prop_map{$line[0]})
  361.       {
  362.         $logindefs->{$login_defs_prop_map{$line[0]}} = $line[1];
  363.       }
  364.     }
  365.  
  366.     close $fh;
  367.   }
  368.   else
  369.   {
  370.     # Put safe defaults for distros/OS that don't have any defaults file
  371.     $logindefs->{"umin"} = '1000';
  372.     $logindefs->{"umax"} = '60000';
  373.     $logindefs->{"gmin"} = '1000';
  374.     $logindefs->{"gmax"} = '60000';
  375.   }
  376.  
  377.   return $logindefs;
  378. }
  379.  
  380. sub get
  381. {
  382.   my ($ifh, @users, %users_hash);
  383.   my (@line, @users);
  384.  
  385.   # Find the passwd file.
  386.   $ifh = &Utils::File::open_read_from_names(@passwd_names);
  387.   return unless ($ifh);
  388.  
  389.   while (<$ifh>)
  390.   {
  391.     chomp;
  392.     # FreeBSD allows comments in the passwd file.
  393.     next if &Utils::Util::ignore_line ($_);
  394.  
  395.     @line  = split ':', $_, -1;
  396.     $login = $line[$LOGIN];
  397.     @comment = split ',', $line[$COMMENT], 5;
  398.  
  399.     # we need to make sure that there are 5 elements
  400.     push @comment, "" while (scalar (@comment) < 5);
  401.     $line[$COMMENT] = [@comment];
  402.  
  403.     $users_hash{$login} = [@line];
  404.   }
  405.  
  406.   &Utils::File::close_file ($ifh);
  407.   $ifh = &Utils::File::open_read_from_names(@shadow_names);
  408.  
  409.   if ($ifh)
  410.   {
  411.     while (<$ifh>)
  412.     {
  413.       chomp;
  414.  
  415.       # FreeBSD allows comments in the shadow passwd file.
  416.       next if &Utils::Util::ignore_line ($_);
  417.  
  418.       @line = split ':', $_, -1;
  419.       $login = shift @line;
  420.       $passwd = shift @line;
  421.  
  422.       # do not add data if the user isn't present
  423.       next if (!exists $users_hash{$login});
  424.  
  425.       $users_hash{$login}[$PASSWD] = $passwd;
  426.  
  427.       # FIXME: add the rest of the fields?
  428.       #push @{$$users_hash{$login}}, @line;
  429.     }
  430.  
  431.     &Utils::File::close_file ($ifh);
  432.   }
  433.  
  434.   # transform the hash into an array
  435.   foreach $login (keys %users_hash)
  436.   {
  437.     push @users, $users_hash{$login};
  438.   }
  439.  
  440.   return \@users;
  441. }
  442.  
  443. sub del_user
  444. {
  445.     my ($user) = @_;
  446.   my ($command);
  447.     
  448.   if ($Utils::Backend::tool{"system"} eq "FreeBSD")
  449.   {
  450.     $command = "$cmd_pw userdel -n \'" . $$user[$LOGIN] . "\' ";
  451.   }
  452.   else
  453.   {
  454.     if ($cmd_deluser)
  455.     {
  456.       $command = "$cmd_deluser '". $$user[$LOGIN] . "'";
  457.     }
  458.     else
  459.     {
  460.       $command = "$cmd_userdel \'" . $$user[$LOGIN] . "\'";
  461.     }
  462.   }
  463.  
  464.   &Utils::File::run ($command);
  465. }
  466.  
  467. sub change_user_chfn
  468. {
  469.   my ($login, $old_comment, $comment) = @_;
  470.   my ($fname, $office, $office_phone, $home_phone);
  471.   my ($command, $str);
  472.  
  473.   return if !$login;
  474.  
  475.   # Compare old and new data
  476.   return if (Utils::Util::struct_eq ($old_comment, $comment));
  477.   $str = join (",", @$comment);
  478.  
  479.   if ($Utils::Backend::tool{"system"} eq "FreeBSD")
  480.   {
  481.     $command = "$cmd_pw usermod -n " . $login . " -c \'" . $str . "\'";
  482.   }
  483.   else
  484.   {
  485.     $command = "$cmd_usermod -c \'" . $str . "\' " . $login;
  486.   }
  487.  
  488.   &Utils::File::run ($command);
  489. }
  490.  
  491. # modifies /etc/shadow directly, not good practice,
  492. # but better than passing clean passwords around
  493. sub modify_shadow_password
  494. {
  495.   my ($login, $password) = @_;
  496.   my ($buffer, $i, @arr);
  497.  
  498.   $buffer = &Utils::File::load_buffer (@shadow_names);
  499.   return if (!$buffer);
  500.   $i = 0;
  501.  
  502.   while ($$buffer[$i])
  503.   {
  504.     @arr = split ':', $$buffer[$i], -1;
  505.  
  506.     if ($arr[0] eq $login)
  507.     {
  508.       $arr[1] = $password;
  509.       $$buffer[$i] = join (':', @arr) . "\n";
  510.       last;
  511.     }
  512.  
  513.     $i++;
  514.   }
  515.  
  516.   &Utils::File::save_buffer ($buffer, @shadow_names);
  517. }
  518.  
  519. sub set_passwd
  520. {
  521.   my ($login, $password) = @_;
  522.   my ($pwdpipe, $command);
  523.  
  524.   if ($Utils::Backend::tool{"system"} eq "FreeBSD")
  525.   {
  526.  
  527.     $command = "$cmd_pw usermod -H 0";
  528.     $pwdpipe = &Utils::File::run_pipe_write ($command);
  529.     print $pwdpipe $password;
  530.     &Utils::File::close_file ($pwdpipe);
  531.   }
  532.   elsif ($Utils::Backend::tool{"system"} eq "SunOS")
  533.   {
  534.     &modify_shadow_password ($login, $password);
  535.   }
  536.   else
  537.   {
  538.     $command = "$cmd_usermod " .
  539.         " -p '" . $password . "' " . $login;
  540.  
  541.     &Utils::File::run ($command);
  542.   }
  543. }
  544.  
  545. sub add_user
  546. {
  547.     my ($user) = @_;
  548.     my ($home_parents, $tool_mkdir);
  549.   
  550.   $tool_mkdir = &Utils::File::locate_tool ("mkdir");
  551.  
  552.   if ($Utils::Backend::tool{"system"} eq "FreeBSD")
  553.   {
  554.     my $pwdpipe;
  555.     my $home;
  556.  
  557.     # FreeBSD doesn't create the home directory
  558.     $home = $$user[$HOME];
  559.     &Utils::File::run ("$tool_mkdir -p $home");
  560.  
  561.     $command = "$cmd_pw useradd " .
  562.         " -n \'" . $$user[$LOGIN] . "\'" .
  563.         " -u \'" . $$user[$UID]   . "\'" .
  564.         " -d \'" . $$user[$HOME]  . "\'" .
  565.         " -g \'" . $$user[$GID]   . "\'" .
  566.         " -s \'" . $$user[$SHELL] . "\'" .
  567.         " -H 0"; # pw(8) reads password from STDIN
  568.  
  569.     $pwdpipe = &Utils::File::run_pipe_write ($command);
  570.     print $pwdpipe $$user[$PASSWD];
  571.     &Utils::File::close_file ($pwdpipe);
  572.   }
  573.   elsif ($Utils::Backend::tool{"system"} eq "SunOS")
  574.   {
  575.     $home_parents = $$user[$HOME];
  576.     $home_parents =~ s/\/+[^\/]+\/*$//;
  577.     &Utils::File::run ("$tool_mkdir -p $home_parents");
  578.  
  579.     $command = "$cmd_useradd" .
  580.         " -d \'" . $$user[$HOME]  . "\'" .
  581.         " -g \'" . $$user[$GID]   . "\'" .
  582.         " -s \'" . $$user[$SHELL] . "\'" .
  583.         " -u \'" . $$user[$UID]   . "\'" .
  584.         " \'"    . $$user[$LOGIN] . "\'";
  585.  
  586.     &Utils::File::run ($command);
  587.     &modify_shadow_password ($$user[$LOGIN], $$user[$PASSWD]);
  588.   }
  589.   else
  590.   {
  591.     $home_parents = $$user[$HOME];
  592.     $home_parents =~ s/\/+[^\/]+\/*$//;
  593.     &Utils::File::run ("$tool_mkdir -p $home_parents");
  594.  
  595.     if ($cmd_adduser &&
  596.         $Utils::Backend::tool{"platform"} !~ /^slackware/ &&
  597.         $Utils::Backend::tool{"platform"} !~ /^archlinux/ &&
  598.         $Utils::Backend::tool{"platform"} !~ /^redhat/)
  599.     {
  600.       # use adduser if available and valid (slackware one is b0rk)
  601.       # set empty gecos fields and password, they will be filled out later
  602.       $command = "$cmd_adduser --gecos '' --disabled-password" .
  603.           " --home \'"  . $$user[$HOME]   . "\'" .
  604.           " --gid \'"   . $$user[$GID]    . "\'" .
  605.           " --shell \'" . $$user[$SHELL]  . "\'" .
  606.           " --uid \'"   . $$user[$UID]    . "\'" .
  607.           " \'"         . $$user[$LOGIN]  . "\'";
  608.  
  609.       &Utils::File::run ($command);
  610.  
  611.       # password can't be set in non-interactive
  612.       # mode with adduser, call usermod instead
  613.       $command = "$cmd_usermod " .
  614.           " -p '" . $$user[$PASSWD] . "' " . $$user[$LOGIN];
  615.  
  616.       &Utils::File::run ($command);
  617.     }
  618.     else
  619.     {
  620.       # fallback to useradd
  621.       $command = "$cmd_useradd -m" .
  622.           " -d \'" . $$user[$HOME]   . "\'" .
  623.           " -g \'" . $$user[$GID]    . "\'" .
  624.           " -p \'" . $$user[$PASSWD] . "\'" .
  625.           " -s \'" . $$user[$SHELL]  . "\'" .
  626.           " -u \'" . $$user[$UID]    . "\'" .
  627.           " \'"    . $$user[$LOGIN]  . "\'";
  628.  
  629.       &Utils::File::run ($command);
  630.     }
  631.   }
  632.  
  633.   &change_user_chfn ($$user[$LOGIN], undef, $$user[$COMMENT]);
  634. }
  635.  
  636. sub change_user
  637. {
  638.   my ($old_user, $new_user) = @_;
  639.     
  640.   if ($Utils::Backend::tool{"system"} eq "FreeBSD")
  641.   {
  642.     my $pwdpipe;
  643.  
  644.     $command = "$cmd_pw usermod \'" . $$old_user[$LOGIN] . "\'" .
  645.         " -l \'" . $$new_user[$LOGIN] . "\'" .
  646.         " -u \'" . $$new_user[$UID]   . "\'" .
  647.         " -d \'" . $$new_user[$HOME]  . "\'" .
  648.         " -g \'" . $$new_user[$GID]   . "\'" .
  649.         " -s \'" . $$new_user[$SHELL] . "\'" .
  650.         " -H 0"; # pw(8) reads password from STDIN
  651.  
  652.     $pwdpipe = &Utils::File::run_pipe_write ($command);
  653.     print $pwdpipe $$new_user[$PASSWD];
  654.     &Utils::File::close_file ($pwdpipe);
  655.   }
  656.   elsif ($Utils::Backend::tool{"system"} eq "SunOS")
  657.   {
  658.     $command = "$cmd_usermod" .
  659.         " -d \'" . $$new_user[$HOME]   . "\'" .
  660.         " -g \'" . $$new_user[$GID]    . "\'" .
  661.         " -l \'" . $$new_user[$LOGIN]  . "\'" .
  662.         " -s \'" . $$new_user[$SHELL]  . "\'" .
  663.         " -u \'" . $$new_user[$UID]    . "\'" .
  664.         " \'" . $$old_user[$LOGIN] . "\'";
  665.  
  666.     &Utils::File::run ($command);
  667.     &modify_shadow_password ($$new_user[$LOGIN], $$new_user[$PASSWD]);
  668.   }
  669.   else
  670.   {
  671.     $command = "$cmd_usermod" .
  672.         " -d \'" . $$new_user[$HOME]   . "\'" .
  673.         " -g \'" . $$new_user[$GID]    . "\'" .
  674.         " -l \'" . $$new_user[$LOGIN]  . "\'" .
  675.         " -p \'" . $$new_user[$PASSWD] . "\'" .
  676.         " -s \'" . $$new_user[$SHELL]  . "\'" .
  677.         " -u \'" . $$new_user[$UID]    . "\'" .
  678.         " \'" . $$old_user[$LOGIN] . "\'";
  679.  
  680.     &Utils::File::run ($command);
  681.   }
  682.  
  683.   &change_user_chfn ($$new_user[$LOGIN], $$old_user[$COMMENT], $$new_user[$COMMENT]);
  684. }
  685.  
  686. sub set_logindefs
  687. {
  688.   my ($config) = @_;
  689.   my ($logindefs, $key, $file);
  690.  
  691.   return unless $config;
  692.  
  693.   &get_login_defs_prop_array ();
  694.  
  695.   foreach $key (@login_defs_names)
  696.   {
  697.     if (-f $key)
  698.     {
  699.       $file = $key;
  700.       last;
  701.     }
  702.   }
  703.  
  704.   unless ($file) 
  705.   {
  706.     &Utils::Report::do_report ("file_open_read_failed", join (", ", @login_defs_names));
  707.     return;
  708.   }
  709.  
  710.   foreach $key (keys (%$config))
  711.   {
  712.     # Write ONLY login.defs values.
  713.     if (exists ($login_defs_prop_map{$key}))
  714.     {
  715.       &Utils::Replace::split ($file, $login_defs_prop_map{$key}, "[ \t]+", $$config{$key});
  716.     }
  717.   }
  718. }
  719.  
  720. sub set
  721. {
  722.   my ($config) = @_;
  723.   my ($old_config, %users);
  724.   my (%config_hash, %old_config_hash);
  725.  
  726.   if ($config)
  727.   {
  728.     # Make backups manually, otherwise they don't get backed up.
  729.     &Utils::File::do_backup ($_) foreach (@passwd_names);
  730.     &Utils::File::do_backup ($_) foreach (@shadow_names);
  731.  
  732.     $old_config = &get ();
  733.  
  734.     foreach $i (@$config) 
  735.     {
  736.       $users{$$i[$LOGIN]} |= 1;
  737.       $config_hash{$$i[$LOGIN]} = $i;
  738.     }
  739.     
  740.     foreach $i (@$old_config)
  741.     {
  742.       $users{$$i[$LOGIN]} |= 2;
  743.       $old_config_hash{$$i[$LOGIN]} = $i;
  744.     }
  745.  
  746.     # Delete all groups that only appeared in the old configuration
  747.     foreach $i (sort (keys (%users)))
  748.     {
  749.       $state = $users{$i};
  750.  
  751.       if ($state == 1)
  752.       {
  753.         # Users with state 1 have been added to the config
  754.         &add_user ($config_hash{$i});
  755.       }
  756.       elsif ($state == 2)
  757.       {
  758.         # Users with state 2 have been deleted from the config
  759.         &del_user ($old_config_hash{$i});
  760.       }
  761.       elsif (($state == 3) &&
  762.              (!Utils::Util::struct_eq ($config_hash{$i}, $old_config_hash{$i})))
  763.       {
  764.         &change_user ($old_config_hash{$i}, $config_hash{$i});
  765.       }
  766.     }
  767.   }
  768. }
  769.  
  770. sub get_user
  771. {
  772.   my ($uid) = @_;
  773.   my ($users) = &get ();
  774.  
  775.   foreach $user (@$users)
  776.   {
  777.     next if ($uid != $$user[$UID]);
  778.     return ($$user[$UID], $$user[$PASSWD], $$user[$COMMENT]);
  779.   }
  780.  
  781.   return ($uid, "", []);
  782. }
  783.  
  784. sub set_user
  785. {
  786.   my ($uid, $passwd, @comment) = @_;
  787.   my ($users) = &get ();
  788.  
  789.   foreach $user (@$users)
  790.   {
  791.     if ($uid == $$user[$UID])
  792.     {
  793.       &set_passwd ($$user[$LOGIN], $passwd);
  794.       &change_user_chfn ($$user[$LOGIN], undef, @comment);
  795.       return;
  796.     }
  797.   }
  798. }
  799.  
  800. sub get_files
  801. {
  802.   my ($arr);
  803.  
  804.   push @$arr, @passwd_names;
  805.   push @$arr, @shadow_names;
  806.  
  807.   return $arr;
  808. }
  809.  
  810. 1;
  811.